package com.whosly.spring.cloud.components.starter.sentry.configure;

import com.whosly.spring.cloud.components.starter.sentry.configure.data.SentryProperties;
import io.sentry.SendCachedEnvelopeFireAndForgetIntegration;
import io.sentry.SendFireAndForgetEnvelopeSender;
import io.sentry.Sentry;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;

import java.time.LocalDate;

/**
 * Sentry 初始化
 */
@Slf4j
public class SentryInitBean implements InitializingBean {

    private SentryProperties sentryProperties;

    public SentryInitBean(SentryProperties sentryProperties) {
        this.sentryProperties = sentryProperties;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.debug("SentryInitBean init start");

        Sentry.init(options -> {
            options.setDsn(sentryProperties.getDsn());

            if(sentryProperties.getSampleRate() != null){
                // 对 n% 的错误进行抽样
                options.setSampleRate(sentryProperties.getSampleRate());
            }
            // Set traces_sample_rate to 1.0 to capture 100% of transactions for performance monitoring.
            // We recommend adjusting this value in production.
            if(sentryProperties.getTracesSampleRate() != null){
                options.setTracesSampleRate(sentryProperties.getTracesSampleRate());
            }

            if(StringUtils.isNotEmpty(sentryProperties.getEnvironment())){
                options.setEnvironment(sentryProperties.getEnvironment());
            }

            // When first trying Sentry it's good to see what the SDK is doing:
            if(sentryProperties.getDebug() != null){
                options.setDebug(sentryProperties.getDebug());
            }

            if(StringUtils.isNotEmpty(sentryProperties.getRelease())){
                options.setRelease(sentryProperties.getRelease());
            }

            if(!ObjectUtils.isEmpty(sentryProperties.getShutdownTimeout())){
                options.setShutdownTimeout(sentryProperties.getShutdownTimeout());
            }
            if(!ObjectUtils.isEmpty(sentryProperties.getFlushTimeoutMillis())){
                options.setFlushTimeoutMillis(sentryProperties.getFlushTimeoutMillis());
            }
            if(!ObjectUtils.isEmpty(sentryProperties.getFlushTimeoutMillis())){
                options.setFlushTimeoutMillis(sentryProperties.getFlushTimeoutMillis());
            }
            options.setConnectionTimeoutMillis(sentryProperties.getConnectionTimeoutMillis());
            options.setReadTimeoutMillis(sentryProperties.getReadTimeoutMillis());
            options.setMaxBreadcrumbs(sentryProperties.getMaxBreadcrumbs());

            // 要启用从属性文件、系统属性或环境变量加载配置enableExternalConfiguration，必须设置为true
            if(!ObjectUtils.isEmpty(sentryProperties.getEnableExternalConfiguration())){
                options.setEnableExternalConfiguration(sentryProperties.getEnableExternalConfiguration());
            }

            // 配置离线缓存的磁盘路径
            // SDK 可以在发生网络错误时将事件存储在磁盘上，如果 Sentry 服务器可访问，则将它们发送到另一个 SDK init 上的 Sentry。
            // 要打开离线缓存，请设置cacheDirPath并添加SendCachedEnvelopeFireAndForgetIntegration到 Sentry 选项
            // 要启用从属性文件、系统属性或环境变量加载配置enableExternalConfiguration，必须设置为true
            if(StringUtils.isNotEmpty(sentryProperties.getCacheDirPath())){
                options.setCacheDirPath(sentryProperties.getCacheDirPath());
                options.addIntegration(
                        new SendCachedEnvelopeFireAndForgetIntegration(
                                new SendFireAndForgetEnvelopeSender(options::getCacheDirPath)
                        )
                );
            }

            // 应用内包含， 逗号分割
            if(StringUtils.isNotEmpty(sentryProperties.getInAppIncludes())){
                String[] inAppIncludesList = StringUtils.split(sentryProperties.getInAppIncludes(), ",");
                if(inAppIncludesList != null && inAppIncludesList.length > 0){
                    for (String inAppInclude : inAppIncludesList) {
                        options.addInAppInclude(StringUtils.trim(inAppInclude));
                    }
                }
            }

            // 应用内排除， 逗号分割
            if(StringUtils.isNotEmpty(sentryProperties.getInAppExcludes())){
                String[] inAppExcludesList = StringUtils.split(sentryProperties.getInAppExcludes(), ",");
                if(inAppExcludesList != null && inAppExcludesList.length > 0){
                    for (String inAppExclude : inAppExcludesList) {
                        options.addInAppExclude(StringUtils.trim(inAppExclude));
                    }
                }
            }

            // 忽略类型的异常， 逗号分割. java.lang.RuntimeException,java.lang.IllegalStateException
            if(StringUtils.isNotEmpty(sentryProperties.getIgnoredExceptionsForType())){
                String[] ignoredExceptionsForTypeList = StringUtils.split(sentryProperties.getIgnoredExceptionsForType(), ",");
                if(ignoredExceptionsForTypeList != null && ignoredExceptionsForTypeList.length > 0){
                    for (String ignoredExceptionsForType : ignoredExceptionsForTypeList) {
                        try{
                            Class<? extends Throwable> exceptionType = (Class<? extends Throwable>) Class.forName(
                                    StringUtils.trim(ignoredExceptionsForType)
                            );

                            options.addIgnoredExceptionForType(exceptionType);
                        }catch (ClassNotFoundException ex){
                            // ignore
                        }
                    }
                }
            }

            options.setBeforeSend((event, hint) -> {
//                // Drop an event altogether:
//                if (event.getTag("SomeTag") != null) {
//                    return null;
//                }
                return event;
            });
        });

        Sentry.configureScope(scope -> {
            // 服务启动时间
            LocalDate date = LocalDate.now();
            scope.setTag("runnerStartDate", date.toString());


//#  tags.first_tag: first-tag-value
//#  tags.second_tag: second-tag-value
        });

        log.debug("SentryInitBean init end");
    }

}
